package com.yunpeng.aidevice.dao.service.impl;

import com.yunpeng.aidevice.common.constant.ConfigConstantValues;
import com.yunpeng.aidevice.common.constant.ConstantValues;
import com.yunpeng.aidevice.common.dto.save.MerchantSaveDTO;
import com.yunpeng.aidevice.common.enums.MerchantStateEnum;
import com.yunpeng.aidevice.common.enums.ResultCodeEnum;
import com.yunpeng.aidevice.common.vo.AppUpdateInfoVO;
import com.yunpeng.aidevice.dao.mapper.entity.MerchantMapper;
import com.yunpeng.aidevice.dao.model.entity.MerchantDO;
import com.yunpeng.aidevice.dao.model.record.DictionariesDO;
import com.yunpeng.aidevice.dao.service.*;
import com.yunpeng.aidevice.dao.util.RelationUpdateUtil;
import com.yunpeng.cache.util.DistributedLockHelper;
import com.yunpeng.common.exception.BizException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * MerchantServiceImpl
 *
 * @author : Moore(hemw)
 * @date : 2020-04-28
 */
@Service
public class MerchantServiceImpl implements IMerchantService {

    /**
     * 日志对象
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(MerchantServiceImpl.class);
    /**
     * 当前服务的实体表名
     */
    private static final String TABLE_NAME = "t_ai_device_merchant";

    @Resource
    private MerchantMapper merchantMapper;

    @Resource
    private ICodeGenerateCommonService codeGenerateCommonService;

    @Resource
    private IUserService userService;

    @Resource
    private IOrganizationService organizationService;

    @Resource
    private IDictionariesService dictionariesService;

    @Override
    /**
     * 新增商户
     *
     * @param merchantSaveDTO
     * @param operatorCode
     * @return
     */
    public Boolean addMerchant(MerchantSaveDTO merchantSaveDTO, String operatorCode) {
        if (merchantSaveDTO == null || StringUtils.isBlank(merchantSaveDTO.getMerchantNumber())) {
            return false;
        }
        MerchantDO merchantDO = new MerchantDO();
        merchantDO.initForNew(operatorCode);
        merchantDO.setMerchantUser(merchantSaveDTO.getMerchantUserName());
        merchantDO.setMerchantUserPhone(merchantSaveDTO.getMerchantUserPhone());
        merchantDO.setMerchantUserEmail(merchantSaveDTO.getMerchantUserEmail());
        merchantDO.setMerchantAddress(merchantSaveDTO.getMerchantAddress());
        if (merchantSaveDTO.getDisabled()) {
            merchantDO.setState(MerchantStateEnum.disabled.getValue());
        } else {
            merchantDO.setState(MerchantStateEnum.normal.getValue());
        }
        merchantDO.setInvalidDate(merchantSaveDTO.getInvalidTime());
        if (merchantSaveDTO.getMerchantImages() != null && merchantSaveDTO.getMerchantImages().size() > 0) {
            merchantDO.setMerchantImages(merchantSaveDTO.getMerchantImages().toJSONString());
        }
        if (merchantSaveDTO.getMerchantNumber() != null) {
            if (merchantMapper.countNumberExists(merchantSaveDTO.getMerchantNumber(), merchantSaveDTO.getTenantCode()) > 0) {
                throw new BizException(ResultCodeEnum.EXISTS_NUMBER_FAILED);
            }
        }
        merchantDO.setNumber(merchantSaveDTO.getMerchantNumber());
        merchantDO.setName(merchantSaveDTO.getMerchantName());
        if (DistributedLockHelper.INSTANCE.getLock(TABLE_NAME, ConfigConstantValues.APPLICATION_NAME)) {
            merchantDO.setCode(codeGenerateCommonService.generateCode(TABLE_NAME));
            try {
                merchantMapper.add(merchantDO);
                //异步新建用户和组织
                CompletableFuture<Boolean> futureLog = CompletableFuture.supplyAsync(() ->
                        {
                            String orgCode = organizationService.addMerchantDefaultOrg(merchantDO, operatorCode);
                            userService.addMerchantDefaultUser(merchantDO, orgCode, operatorCode);
                            return true;
                        }
                );
                return true;
            } catch (Exception ex) {
                LOGGER.error("save merchant info error : {}", merchantDO, ex);
                throw new BizException(ResultCodeEnum.SAVE_DATA_FAILED);
            } finally {
                codeGenerateCommonService.holdCountMinus(TABLE_NAME);
                DistributedLockHelper.INSTANCE.unlock(TABLE_NAME, ConfigConstantValues.APPLICATION_NAME);
            }
        } else {
            return false;
        }
    }

    @Override
    /**
     * 更新商户信息
     *
     * @param merchantSaveDTO 商户保存信息
     * @param operatorCode    操作人代码
     * @return
     */
    public Boolean modify(MerchantSaveDTO merchantSaveDTO, String operatorCode) {
        if (merchantSaveDTO == null || StringUtils.isBlank(merchantSaveDTO.getMerchantNumber())
                || StringUtils.isBlank(merchantSaveDTO.getMerchantCode())) {
            return false;
        }
        MerchantDO merchantDO = getByCode(merchantSaveDTO.getMerchantCode(), merchantSaveDTO.getTenantCode());
        if (merchantDO == null) {
            throw new BizException(ResultCodeEnum.NOT_EXISTS_DATA_FAILED, "不存在此商户");
        }
        Map<String, Object> updateMap = new HashMap<>(16);
        if (StringUtils.isNotBlank(merchantSaveDTO.getMerchantNumber())) {
            if (!merchantDO.getNumber().equals(merchantSaveDTO.getMerchantNumber())) {
                if (merchantMapper.countNumberExistsExcludeCode(merchantSaveDTO.getMerchantNumber(), merchantSaveDTO.getTenantCode(), merchantSaveDTO.getMerchantCode()) > 0) {
                    throw new BizException(ResultCodeEnum.EXISTS_NUMBER_FAILED);
                }
            }
            updateMap.put("number", merchantSaveDTO.getMerchantNumber());
        }
        updateMap.put("update_time", LocalDateTime.now());
        updateMap.put("updater", operatorCode);
        if (StringUtils.isNotBlank(merchantSaveDTO.getMerchantName())) {
            updateMap.put("name", merchantSaveDTO.getMerchantName());
        }
        if (StringUtils.isNotBlank(merchantSaveDTO.getMerchantAddress())) {
            updateMap.put("merchant_address", merchantSaveDTO.getMerchantAddress());
        }
        if (StringUtils.isNotBlank(merchantSaveDTO.getMerchantUserName())) {
            updateMap.put("merchant_user", merchantSaveDTO.getMerchantUserName());
        }
        if (StringUtils.isNotBlank(merchantSaveDTO.getMerchantUserPhone())) {
            updateMap.put("merchant_user_phone", merchantSaveDTO.getMerchantUserPhone());
        }
        if (StringUtils.isNotBlank(merchantSaveDTO.getMerchantUserEmail())) {
            updateMap.put("merchant_user_email", merchantSaveDTO.getMerchantUserEmail());
        }
        if (merchantSaveDTO.getInvalidTime() != null) {
            updateMap.put("invalid_date", merchantSaveDTO.getInvalidTime());
        }
        if (merchantSaveDTO.getMerchantImages() != null && merchantSaveDTO.getMerchantImages().size() > 0) {
            updateMap.put("merchant_images", merchantSaveDTO.getMerchantImages().toJSONString());
        }
        if (merchantSaveDTO.getDisabled()) {
            updateMap.put("state", MerchantStateEnum.disabled.getValue());
        } else {
            updateMap.put("state", MerchantStateEnum.normal.getValue());
        }
        //更新商户负责人信息
        RelationUpdateUtil.INSTANCE.merchantDefaultUserInfoUpdatePush(merchantSaveDTO.getMerchantUserName(),
                merchantSaveDTO.getMerchantUserPhone(),
                merchantSaveDTO.getMerchantUserEmail(),
                merchantSaveDTO.getMerchantCode(),
                merchantSaveDTO.getTenantCode(),
                false);
        return merchantMapper.update(merchantDO.getId(), updateMap) > 0;
    }

    @Override
    /**
     * 更新有效期
     *
     * @param merchantCode
     * @param tenantCode
     * @param operatorCode
     * @param dateTime
     * @return
     */
    public Boolean updateInvalidDate(String merchantCode, String tenantCode, String operatorCode, LocalDateTime dateTime) {
        if (dateTime == null) {
            return false;
        }
        MerchantDO merchantDO = getByCode(merchantCode, tenantCode);
        if (merchantDO == null) {
            throw new BizException(ResultCodeEnum.NOT_EXISTS_DATA_FAILED, "不存在此商户");
        }
        Map<String, Object> updateMap = new HashMap<>(16);
        updateMap.put("update_time", LocalDateTime.now());
        updateMap.put("updater", operatorCode);
        updateMap.put("invalid_date", dateTime);
        return merchantMapper.update(merchantDO.getId(), updateMap) > 0;
    }


    @Override
    /**
     * 根据租户获取商户列表（2000）
     *
     * @param tenantCode
     * @return
     */
    public List<MerchantDO> getByTenant(String tenantCode) {
        if (StringUtils.isBlank(tenantCode)) {
            return new ArrayList<>();
        }
        Map<String, Object> queryMap = new HashMap<>(16);
        queryMap.put("flag", 1);
        queryMap.put("tenant_code", tenantCode);
        return merchantMapper.queryForList(queryMap);
    }

    @Override
    /**
     * 根据代码获取商户对象
     *
     * @param code       商户代码
     * @param tenantCode 租户代码
     * @return
     */
    public MerchantDO getByCode(String code, String tenantCode) {
        if (StringUtils.isBlank(code)) {
            return null;
        }
        if (StringUtils.isBlank(tenantCode)) {
            return null;
        }
        MerchantDO merchantDO = merchantMapper.getByCode(code);
        if (tenantCode.equals(merchantDO.getTenantCode())) {
            return merchantDO;
        }
        return null;
    }

    @Override
    /**
     * 禁用启用商户
     *
     * @param disable
     * @param merchantCode
     * @param tenantCode
     * @param operatorCode
     * @return
     */
    public Boolean enableDisableMerchant(Boolean disable, String merchantCode, String tenantCode, String operatorCode) {
        MerchantDO merchantDO = getByCode(merchantCode, tenantCode);
        if (merchantCode == null) {
            throw new BizException(ResultCodeEnum.NOT_EXISTS_DATA_FAILED, "不存在此商户");
        }
        Map<String, Object> updateMap = new HashMap<>(16);
        updateMap.put("update_time", LocalDateTime.now());
        updateMap.put("updater", operatorCode);
        if (disable) {
            updateMap.put("state", MerchantStateEnum.disabled.getValue());
        } else {
            updateMap.put("state", MerchantStateEnum.normal.getValue());
        }
        return merchantMapper.update(merchantDO.getId(), updateMap) > 0;
    }

    @Override
    /**
     * 设置app更新时间
     *
     * @param startTime
     * @param endTime
     * @param merchantCode
     * @param tenantCode
     * @param operatorCode
     * @return
     */
    public Boolean updateAppUpdateTime(Short startTime, Short endTime, String merchantCode, String tenantCode, String operatorCode) {
        MerchantDO merchantDO = getByCode(merchantCode, tenantCode);
        if (merchantCode == null) {
            throw new BizException(ResultCodeEnum.NOT_EXISTS_DATA_FAILED, "不存在此商户");
        }
        Map<String, Object> updateMap = new HashMap<>(16);
        updateMap.put("update_time", LocalDateTime.now());
        updateMap.put("updater", operatorCode);
        updateMap.put("device_update_start_time", startTime);
        updateMap.put("device_update_end_time", endTime);
        return merchantMapper.update(merchantDO.getId(), updateMap) > 0;
    }

    @Override
    /**
     * 获取商户app更新设定信息
     * 优先使用商户设定的时间，不存在则返回全局配置
     *
     * @param merchantCode
     * @param tenantCode
     * @return
     */
    public AppUpdateInfoVO getAppUpdateInfoVO(String merchantCode, String tenantCode) {
        List<DictionariesDO> dictionariesDOList = dictionariesService.queryDictionariesList(ConfigConstantValues.SYSTEM_DOMAIN, ConfigConstantValues.APP_UPDATE_GROUP);
        AppUpdateInfoVO appUpdateInfoVO = initNewEmptyAppUpdateInfo();
        //设置商户app更新信息
        if (dictionariesDOList != null && dictionariesDOList.size() > 0) {
            for (DictionariesDO dictionariesDO : dictionariesDOList) {
                if (ConstantValues.APP_VERSION.equalsIgnoreCase(dictionariesDO.getKeyName())) {
                    appUpdateInfoVO.setAppVersion(dictionariesDO.getKeyValue());
                    continue;
                }
                if (ConstantValues.SELF_UPDATE_URL.equalsIgnoreCase(dictionariesDO.getKeyName())) {
                    appUpdateInfoVO.setSelfUpdateUrl(dictionariesDO.getKeyValue());
                    continue;
                }
                if (ConstantValues.DW_VERSION.equalsIgnoreCase(dictionariesDO.getKeyName())) {
                    appUpdateInfoVO.setDwVersion(dictionariesDO.getKeyValue());
                    continue;
                }
                if (ConstantValues.DW_UPDATE_URL.equalsIgnoreCase(dictionariesDO.getKeyName())) {
                    appUpdateInfoVO.setDwUpdateUrl(dictionariesDO.getKeyValue());
                    continue;
                }
                if (ConstantValues.START_TIME.equalsIgnoreCase(dictionariesDO.getKeyName())) {
                    appUpdateInfoVO.setStartTime(Short.parseShort(dictionariesDO.getKeyValue()));
                    continue;
                }
                if (ConstantValues.END_TIME.equalsIgnoreCase(dictionariesDO.getKeyName())) {
                    appUpdateInfoVO.setEndTime(Short.parseShort(dictionariesDO.getKeyValue()));
                }
            }
        }
        //优先使用商户设定的时间，不存在则返回全局配置
        if (StringUtils.isBlank(merchantCode) || StringUtils.isBlank(tenantCode)) {
            return appUpdateInfoVO;
        }
        MerchantDO merchantDO = getByCode(merchantCode, tenantCode);
        if (merchantDO == null) {
            return appUpdateInfoVO;
        }
        if (merchantDO.getDeviceUpdateStartTime() != null && merchantDO.getDeviceUpdateEndTime() != null) {
            appUpdateInfoVO.setStartTime(merchantDO.getDeviceUpdateStartTime());
            appUpdateInfoVO.setEndTime(merchantDO.getDeviceUpdateEndTime());
        }
        return appUpdateInfoVO;
    }

    private AppUpdateInfoVO initNewEmptyAppUpdateInfo() {
        AppUpdateInfoVO appUpdateInfoVO = new AppUpdateInfoVO();
        appUpdateInfoVO.setStartTime(Short.valueOf("0"));
        appUpdateInfoVO.setEndTime(Short.valueOf("1"));
        appUpdateInfoVO.setAppVersion("0");
        appUpdateInfoVO.setDwVersion("0");
        appUpdateInfoVO.setSelfUpdateUrl("");
        appUpdateInfoVO.setDwUpdateUrl("");
        return appUpdateInfoVO;
    }
}
